package com.superb.system.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.stp.StpUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.superb.common.core.annotation.SuperbDataScope;
import com.superb.common.core.annotation.SuperbIgnoreTenant;
import com.superb.common.core.annotation.SuperbRestMapping;
import com.superb.common.core.enums.DataScope;
import com.superb.common.core.model.Result;
import com.superb.common.database.entity.BaseEntity;
import com.superb.common.redis.key.KeyType;
import com.superb.common.redis.key.RedisKey;
import com.superb.common.redis.utils.RedisUtils;
import com.superb.common.security.entity.Organization;
import com.superb.common.security.entity.SuperbTenant;
import com.superb.common.security.entity.SuperbUser;
import com.superb.common.security.entity.SuperbUserDataScope;
import com.superb.common.utils.HeardersUtils;
import com.superb.system.api.entity.SystemTenant;
import com.superb.system.api.entity.UserDataScope;
import com.superb.system.service.*;
import io.swagger.v3.oas.annotations.Hidden;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * @Author: ajie
 * @CreateTime: 2024-05-15 16:29
 */
@Slf4j
@Hidden
@SuperbDataScope
@SuperbRestMapping("security")
public class SecurityController {

    @Resource
    private SystemTenantService tenantService;
    @Resource
    private SystemUserService userService;
    @Resource
    private SystemRoleService roleService;
    @Resource
    private SystemPermissionService permissionService;
    @Resource
    private SystemOrganizationService organizationService;
    @Resource
    private UserDataScopeService userDataScopeService;

    @SaIgnore
    @SuperbIgnoreTenant
    @GetMapping("getTenantInfo")
    public Result<SuperbTenant> getTenantInfo() {
        RedisKey key = new RedisKey(KeyType.TIME, Duration.ofHours(5),"info");
        SuperbTenant superbTenant = RedisUtils.build().value().getNullSet(key, () -> {
            LambdaQueryWrapper<SystemTenant> lqw = new LambdaQueryWrapper<>();
            lqw.eq(SystemTenant::getTenantKey, HeardersUtils.getTenantId());
            SystemTenant tenant = tenantService.getOne(lqw);
            tenant.setTenantId(tenant.getTenantKey());
            return JSON.parseObject(JSON.toJSONString(tenant), SuperbTenant.class);
        }, (redisUtils) -> redisUtils.value().get(key));
        return Result.success(superbTenant);
    }

    /**
     * 获取部门信息
     *
     * @return
     */
    @GetMapping("getOrganization")
    public Result<Organization> getOrganization() {
        RedisKey key = new RedisKey(KeyType.TIME, Duration.ofHours(5),"organization:" + HeardersUtils.getOrganizetionId());
        Organization organization = RedisUtils.build().value().getNullSet(key, () -> organizationService.getById(HeardersUtils.getOrganizetionId()),
                (redisUtils) -> redisUtils.value().get(key));
        return Result.success(organization);
    }

    /**
     * 获取本部门及子部门id
     *
     * @return
     */
    @GetMapping("getOrganizationIds/{organId}")
    public Result<List<String>> getOrganizationIds(@PathVariable String organId) {
        RedisKey key = new RedisKey(KeyType.TIME, Duration.ofHours(5),"organizationIds:" + organId);
        List<String> organizationIds = RedisUtils.build().value().getNullSet(key, () -> {
            List<String> list = new ArrayList<>();
            list.add(organId);
            organizationService.getIdAndSub(list, organId);
            return list;
        }, (redisUtils) -> redisUtils.value().get(key));
        return Result.success(organizationIds);
    }

    @GetMapping("getUserById/{id}")
    public Result<SuperbUser> getUserById(@PathVariable String id) {
        RedisKey key = new RedisKey(KeyType.PER, "userInfo:" + id);
        SuperbUser superbUser = RedisUtils.build().hash().getNullSet(key, "info", () -> userService.getInfoById(id),
                (redisUtils) -> redisUtils.hash().get(key, "info", SuperbUser.class));
        return Result.success(superbUser);
    }

    @GetMapping("getUserRoleList/{id}")
    public Result<List<String>> getUserRoleList(@PathVariable String id) {
        RedisKey key = new RedisKey(KeyType.PER, "userInfo:" + id + ":organId:" + HeardersUtils.getOrganizetionId());
        List<String> roles = RedisUtils.build().hash().getNullSet(key, "role", () -> roleService.listByUserId(id),
                (redisUtils) -> redisUtils.hash().getArray(key, "role", String.class));
        return Result.success(roles);
    }

    @GetMapping("getUserPermissionList/{userId}")
    public Result<List<String>> getUserPermissionList(@PathVariable String userId) {
        RedisKey key = new RedisKey(KeyType.PER, "userInfo:" + userId + ":organId:" + HeardersUtils.getOrganizetionId());
        List<String> permissions = RedisUtils.build().hash().getNullSet(key, "permissions", () -> permissionService.listByUserId(userId),
                (redisUtils) -> redisUtils.hash().getArray(key, "permissions", String.class));
        return Result.success(permissions);
    }

    @GetMapping("getUserDataScope")
    public Result<SuperbUserDataScope> getUserDataScope() {
        String userId = StpUtil.getLoginIdAsString();
        String organizetionId = HeardersUtils.getOrganizetionId();
        RedisKey key = new RedisKey(KeyType.PER, "userInfo:" + userId + ":organId:" + organizetionId);
        SuperbUserDataScope dataScope = RedisUtils.build().hash().getNullSet(key, "dataScope", () -> {
            QueryWrapper<UserDataScope> lqw = new QueryWrapper<>();
            lqw.select("data_scope_type", "data_scope_organ_id", "data_scope_organ_type");
            lqw.lambda().eq(UserDataScope::getUserId, userId).eq(UserDataScope::getOrganId, organizetionId);
            UserDataScope userDataScope = userDataScopeService.getOne(lqw);
            return JSON.to(SuperbUserDataScope.class, JSON.toJSONString(userDataScope));
        }, redis -> redis.hash().get(key, "dataScope"));
        return Result.success(dataScope);
    }

    /**
     * 获取是否存在索引
     * @param table
     * @param column
     * @return
     */
    @SaIgnore
    @GetMapping("getDatabaseIndex/{table}/{column}")
    public Result<String> getDatabaseIndex(@PathVariable String table, @PathVariable String column) {
        return Result.success("", tenantService.getIndex(table, column));
    }

    /**
     * 获取是否存在索引
     * @param table
     * @param column
     * @return
     */
    @SaIgnore
    @GetMapping("getExistColumn/{table}/{column}")
    public Result<Boolean> getExistColumn(@PathVariable String table, @PathVariable String column) {
        return Result.success("", tenantService.getExistColumn(table, column));
    }

}
